package cn.tedu.csmall.passport.service.impl;

import cn.tedu.csmall.passport.ex.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.pojo.dto.AdminAddNewDTO;
import cn.tedu.csmall.passport.pojo.dto.AdminLoginDTO;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.IAdminService;
import cn.tedu.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.*;

@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {
    @Value("${csmall.jwt.secret-key}")
    private String secretKey;
    @Value("${csmall.jwt.duration-in-minute}")
    private long durationInMinute;
    @Autowired
    private  AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        Authentication authentication
                = new UsernamePasswordAuthenticationToken(
                        adminLoginDTO.getUsername(), adminLoginDTO.getPassword());
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.debug("认证通过，认证管理器返回：{}", authenticateResult);

        // 从认证结果中获取所需的数据，将用于生成JWT
        Object principal = authenticateResult.getPrincipal();
        log.debug("认证结果中的当事人类型：{}", principal.getClass().getName());
        AdminDetails adminDetails = (AdminDetails) principal;
        String username = adminDetails.getUsername();
        Long id = adminDetails.getId();
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();
        String authoritiesJsonString =JSON.toJSONString(authorities);


        // 生成JWT数据时，需要填充装到JWT中的数据
        Map<String, Object> claims = new HashMap<>();
         claims.put("id", id);
        claims.put("username", username);
        claims.put("authoritiesJsonString", authoritiesJsonString);
        log.debug("向JWT中存入id：{}", id);
        log.debug("向JWT中存入username：{}", username);
        log.debug("向JWT中存入authoritiesJsonString：{}", authoritiesJsonString);
        // 以下是生成JWT的固定代码
        //String secretKey = "a9F8ujGFDhjgvfd3SA90ukEDS";
        Date date = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000L);
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                // Signature
                .setExpiration(date)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("生成的JWT：{}", jwt);
        return jwt;
        //SecurityContextHolder.getContext().setAuthentication(authenticate); 使用了Session,不推荐使用
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        //调用adminMapper的int countByUsername(String username)执行统计查询
        //判断统计结果是否大于0
        //是:抛出异常(ERR_CONFLICT:电子邮箱被占用)

        //创建Admin对象
        //调用adminMapper的int insert(Admin admin)方法,执行插入管理员数据,获取返回值
        log.debug("开始处理【添加管理员】的业务，参数：{}", adminAddNewDTO);
        {
            // 从参数对象中获取管理员名称
            String adminName = adminAddNewDTO.getUsername();
            // 检查管理员名称是否已经被占用（管理员表中是否已经存在此名称的数据）
            log.debug("检查管理员名称是否已经被占用");
            int count = adminMapper.countByUsername(adminName);
            if (count > 0) {
                // 是：管理员名称已经被占用，添加管理员失败，抛出异常
                String message = "添加管理员失败，管理员名称已经被占用！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        {
            // 从参数对象中获取手机号码
            String phone = adminAddNewDTO.getPhone();
            // 检查手机号码是否已经被占用（管理员表中是否已经存在此手机号码的数据）
            log.debug("检查手机号码是否已经被占用");
            int count = adminMapper.countByPhone(phone);
            if (count > 0) {
                // 是：手机号码已经被占用，添加管理员失败，抛出异常
                String message = "添加管理员失败，手机号码已经被占用！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        {
            // 从参数对象中获取电子邮箱号
            String email = adminAddNewDTO.getEmail();
            // 检查电子邮箱号是否已经被占用（管理员表中是否已经存在此电子邮箱号的数据）
            log.debug("检查电子邮箱号是否已经被占用");
            int count = adminMapper.countByEmail(email);
            if (count > 0) {
                // 是：电子邮箱号已经被占用，添加管理员失败，抛出异常
                String message = "添加管理员失败，电子邮箱号已经被占用！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }
        // 否：管理员名称、手机号码,电子邮箱号没有被占用，则向管理员表中插入数据
        log.debug("管理员名称没有被占用，将向管理员表中插入数据");
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewDTO, admin);
        admin.setLoginCount(0);
        admin.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
        log.debug("即将插入管理员数据：{}", admin);
        int rows = adminMapper.insert(admin);
        if (rows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再尝试！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("插入管理员数据完成");
    }

    @Override
    public void delete(Long id) {
        log.debug("开始处理【根据id删除管理员】的业务，参数：{}", id);
        //id值为1的管理员不允许删除
        if(id==1){
            String message = "删除管理员失败，尝试访问的数据不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        // 调用Mapper对象的getStandardById()执行查询
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        // 判断查询结果是否为null
        if (queryResult == null) {
            // 是：无此id对应的数据，将不允许执行删除操作，则抛出异常
            String message = "删除管理员失败，尝试访问的数据不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 调用Mapper对象的deleteById()方法执行删除
        log.debug("即将执行删除，参数：{}", id);
        int rows = adminMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        // 删除管理员与角色的关联数据
        rows = adminRoleMapper.deleteByAdminId(id);
        if (rows < 1) {
            // 是：抛出异常（ERR_DELETE：服务器忙）
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理【查询管理员列表】的业务，无参数");
        List<AdminListItemVO> list = adminMapper.list();
        Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()){
            AdminListItemVO item = iterator.next();
            if(item.getId() == 1) {
                iterator.remove();
                break;
            }
        }
        return list;
    }

    @Override
    public void setEnable(Long id) {
        log.debug("开始处理【根据id启用管理员】的业务，参数：{}", id);
        updateEnableById(id,1);
    }

    @Override
    public void setDisable(Long id) {
        log.debug("开始处理【根据id禁用管理员】的业务，参数：{}", id);
        updateEnableById(id,0);
    }

    private void updateEnableById(Long id, Integer enable){
        String[] s = {"禁用","启用"};

        if(id.equals(1)){
            // 是：id对应的管理员信息不存在
            String message = s[enable] + "管理员失败" ;
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 调用Mapper对象的getStandardById()执行查询
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        // 判断查询结果是否为null
        if (queryResult == null) {
            // 是：无此id对应的数据，将不允许执行启用、禁用管理员操作，则抛出异常
            String message = s[enable] + "管理员失败，尝试访问的数据不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        //判断查询结果中的enable与方法参数enable是否相同
        if(queryResult.getEnable().equals(enable)){
            // 是：查询结果中的enable与方法参数enable相同，数据冲突，则抛出异常
            String message = s[enable] + "管理员失败,管理员账号已处于" + s[enable] + "状态! ";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //准备执行更新
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        // 调用Mapper对象的update(Admin admin)方法执行启用、禁用管理员
        int rows = adminMapper.update(admin);
        if(rows != 1){
            String message = s[enable] + "管理员，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }

    }
}
